home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1994 by Jon Dart. All Rights Reserved.
-
- #include "board.h"
- #include "rmove.h"
- #include "constant.h"
- #include "bhash.h"
- #include "util.h"
- #include "bearing.h"
- #include <strstream.h>
- #include <ctype.h>
-
- enum {BoardSize = 64};
-
- void Board::set_secondary_vars()
- {
- int index[2], i;
-
- index[Black] = index[White] = 0;
-
- for (i=0;i<16;i++)
- my_PiecePos[i][White] = my_PiecePos[i][Black] = Square::Invalid();
- my_Material[White].clear();
- my_Material[Black].clear();
- for (i=0;i<8;i++)
- {
- my_PFileCount[i][White] = my_PFileCount[i][Black] = 0;
- my_RFileCount[i][White] = my_RFileCount[i][Black] = 0;
- }
- for (i=0;i<BoardSize;i++)
- {
- Square sq(i);
- if (!my_Contents[sq].IsEmpty())
- {
- const Piece piece = my_Contents[sq];
- const ColorType color = piece.Color();
- my_PiecePos[index[color]++][color] = sq;
- my_Material[color].add_piece(piece.Type());
- if (piece.Type() == Piece::King)
- my_KingPos[color] = sq;
- if (piece.Type() == Piece::Pawn)
- {
- my_PFileCount[sq.File()-1][color]++;
- }
- else if (piece.Type() == Piece::Rook)
- {
- my_RFileCount[sq.File()-1][color]++;
- }
- }
- }
- my_HashCode = Board_Hash::HashCode(*this);
- my_attacks.clear();
- my_attacks.compute_attacks(*this,White);
- my_attacks.compute_attacks(*this,Black);
- }
-
- void Board::Reset()
- {
- static Piece::PieceType pieces[] =
- {
- Piece::Rook,
- Piece::Knight,
- Piece::Bishop,
- Piece::Queen,
- Piece::King,
- Piece::Bishop,
- Piece::Knight,
- Piece::Rook
- };
-
- my_Side = White;
-
- for (int i=0;i<BoardSize;i++)
- {
- const Square sq(i);
- if (sq.Rank(White) == 1)
- my_Contents[sq] = Piece( pieces[sq.File()-1], White );
- else if (sq.Rank(Black) == 1)
- my_Contents[sq] = Piece( pieces[sq.File()-1], Black );
- else if (sq.Rank(White) == 2)
- my_Contents[sq] = Piece( Piece::Pawn, White);
- else if (sq.Rank(Black) == 2)
- my_Contents[sq] = Piece( Piece::Pawn, Black);
- else
- my_Contents[sq] = Piece::EmptyPiece();
- }
- my_EnPassantSq[White] = my_EnPassantSq[Black] = Square::Invalid();
- my_CastleStatus[White] = my_CastleStatus[Black] = CanCastleEitherSide;
- set_secondary_vars();
- }
-
- Board::Board()
- {
- Reset();
- }
-
- #ifdef RANGE_CHECK
- const Piece &Board::operator[]( const Square sq ) const
- {
- assert(sq.OnBoard());
- return my_Contents[sq];
- }
- #endif
-
- Piece Board::GetPiece( const Square start, const int dir, Square &dest ) const
- // returns 1st piece in the given direction from "start". Also
- // sets "dest", where it is
- {
- dest = start;
- do {
- dest = dest + dir;
- } while (!dest.OnEdge() && my_Contents[dest].IsEmpty());
-
- return my_Contents[dest];
- }
-
-
- Board::~Board()
- {
- }
-
- void Board::UpdateCastleStatus( const ColorType side,
- const Square sq )
- // after a move of or capture of the rook on 'sq', update castle status
- // for 'side'
- {
- CastleType cs = CastleStatus(side);
- if ((cs != CastledKSide) && (cs != CastledQSide))
- {
- if (sq.File() == 1) // Queen Rook moved or captured
- {
- if (cs == CanCastleEitherSide)
- my_CastleStatus[side] = CanCastleKSide;
- else if (cs == CanCastleQSide)
- my_CastleStatus[side] = CantCastleEitherSide;
- }
- else if (sq.File() == 8) // King Rook moved or captured
- {
- if (cs == CanCastleEitherSide)
- my_CastleStatus[side] = CanCastleQSide;
- else if (cs == CanCastleKSide)
- my_CastleStatus[side] = CantCastleEitherSide;
- }
- }
- }
-
- int Board::Direction( const Square &sq1, const Square &sq2 ) const
- {
- if (sq2 == sq1)
- return 0;
- int offset;
- int abs = (sq2 > sq1) ? (int)sq2 - (int)sq1 : (int)sq1 - (int)sq2;
- if (sq1.File() == sq2.File())
- offset = RankIncr;
- else if (sq1.Rank(White) == sq2.Rank(White))
- offset = 1;
- else if (sq1.Color() == sq2.Color())
- {
- if (abs % (RankIncr+1) == 0)
- offset = RankIncr+1;
- else if (abs % (RankIncr-1) == 0)
- offset = RankIncr-1;
- else
- return 0;
- }
- else
- return 0;
- return (sq2 > sq1) ? offset : -offset;
- }
-
- int Board::Between( const Square &sq1, const Square &sq2,
- Square *squares) const
- {
- int offset = Direction(sq1,sq2);
- Square sq(sq1);
- int n = 0;
- for (;;)
- {
- sq += offset;
- if (sq == sq2)
- break;
- squares[n++] = sq;
- }
- return n;
- }
-
-
- Boolean Board::Clear( const Square &sq1, const Square &sq2 ) const
- {
- Square BtwnSquares[9];
- int m = Between(sq1,sq2,BtwnSquares);
- Boolean is_clear = True;
- if (m == 0)
- return True;
- else
- {
- int k = 0;
- do
- {
- is_clear = my_Contents[BtwnSquares[k++]].IsEmpty();
- } while (is_clear && (k<m));
- }
- return is_clear;
- }
-
- void Board::MakeMove( const ExtendedMove &move )
- {
- int i,j;
- const ColorType oside = OppositeSide();
- const ColorType side = Side();
- Square kp,target;
-
- if (move.IsNull())
- {
- my_Side = oside;
- Board_Hash::UpdateHash( *this, move, my_HashCode, my_HashCode );
- return;
- }
- else
- Board_Hash::UpdateHash( *this, move, my_HashCode, my_HashCode );
-
-
- if (move.Special() == ExtendedMove::KCastle)
- {
- const Square kp = KingPos(side);
- my_attacks.remove_attacks(*this,kp,side);
- my_attacks.remove_attacks(*this,kp+3,side);
- i = 0;
- while (i < 16 && PiecePos(side,i) != kp)
- i++;
- assert(i<16);
- my_KingPos[side] = kp + 2;
- my_PiecePos[i][side] = my_KingPos[side];
- my_CastleStatus[side] = CastledKSide;
- // find old square of rook
- Square oldrooksq = kp + 3;
- Square newrooksq = kp + 1;
- i = 0;
- while (i < 16 && PiecePos(side,i) != oldrooksq)
- i++;
- assert(i<16);
- my_PiecePos[i][side] = newrooksq; // update rook position
- my_Contents[kp] = my_Contents[oldrooksq] = Piece::EmptyPiece();
- my_Contents[newrooksq] = Piece(Piece::Rook,side);
- my_Contents[kp+2] = Piece(Piece::King,side);
- my_RFileCount[oldrooksq.File()-1][side]--;
- my_RFileCount[newrooksq.File()-1][side]++;
- my_attacks.add_attacks(*this,kp+1,side);
- my_attacks.add_attacks(*this,kp+2,side);
- my_attacks.add_discovered_attacks(*this,
- kp,kp+1);
- }
- else if (move.Special() == ExtendedMove::QCastle)
- {
- const Square kp = KingPos(side);
- my_attacks.remove_attacks(*this,kp,side);
- my_attacks.remove_attacks(*this,kp-4,side);
- i = 0;
- while (i < 16 && PiecePos(side,i) != kp)
- i++;
- assert(i < 16);
- my_KingPos[side] = kp - 2;
- my_PiecePos[i][side] = my_KingPos[side];
- my_CastleStatus[side] = CastledQSide;
- // find old square of rook
- Square oldrooksq = kp - 4;
- Square newrooksq = kp - 1;
- i = 0;
- while (i < 16 && PiecePos(side,i) != oldrooksq)
- i++;
- assert(i<16);
- my_PiecePos[i][side] = newrooksq; // update rook position
- my_Contents[kp] = my_Contents[oldrooksq] = Piece::EmptyPiece();
- my_Contents[newrooksq] = Piece(Piece::Rook,side);
- my_Contents[kp-2] = Piece(Piece::King,side);
- my_RFileCount[oldrooksq.File()-1][side]--;
- my_RFileCount[newrooksq.File()-1][side]++;
- my_attacks.add_attacks(*this,kp-1,side);
- my_attacks.add_attacks(*this,kp-2,side);
- my_attacks.add_discovered_attacks(*this,
- kp,kp-1);
- }
- else // not castling
- {
- Square target;
- if (move.Special() == ExtendedMove::EnPassant)
- target = my_EnPassantSq[oside];
- else
- target = move.DestSquare();
- my_attacks.remove_attacks(*this,move.StartSquare(),side);
- Square sq;
- i = 0;
- j = -1;
- while (i < 16 && ((sq = PiecePos(side,i)) != move.StartSquare()))
- {
- if (sq == Square::Invalid() && j==-1)
- j = i;
- i++;
- }
- assert (i < 16);
- // keep pieces near the start of the PiecePos array, if possible:
- if (j == -1)
- my_PiecePos[i][side] = move.DestSquare();
- else
- {
- my_PiecePos[j][side] = move.DestSquare();
- my_PiecePos[i][side] = Square::Invalid();
- }
- if (!move.Capture().IsEmpty())
- my_attacks.remove_attacks(*this,target,oside);
- if (move.Special() == ExtendedMove::Promotion)
- my_Contents[move.DestSquare()] = Piece(move.PromoteTo(),side);
- else
- my_Contents[move.DestSquare()] = move.PieceMoved();
- my_Contents[move.StartSquare()] = Piece::EmptyPiece();
- my_EnPassantSq[side] = Square::Invalid();
- if (move.PieceMoved().Type() == Piece::King)
- {
- my_KingPos[side] = move.DestSquare();
- if ((CastleStatus(side) != CastledQSide) &&
- (CastleStatus(side) != CastledKSide))
- my_CastleStatus[side] = CantCastleEitherSide;
- }
- else if (move.PieceMoved().Type() == Piece::Rook)
- {
- my_RFileCount[move.StartSquare().File()-1][side]--;
- my_RFileCount[move.DestSquare().File()-1][side]++;
- UpdateCastleStatus(side,move.StartSquare());
- }
- else if (move.PieceMoved().Type() == Piece::Pawn)
- {
- if (Util::Abs(move.StartSquare().Rank(side) -
- move.DestSquare().Rank(side)) == 2)
- {
- my_EnPassantSq[side] = move.DestSquare();
- }
- if (move.Special() == ExtendedMove::Promotion)
- {
- my_Material[side].remove_piece(Piece::Pawn);
- my_Material[side].add_piece(move.PromoteTo());
- if (move.PromoteTo() == Piece::Rook)
- {
- my_RFileCount[move.StartSquare().File()-1][side]--;
- my_RFileCount[move.DestSquare().File()-1][side]++;
- }
- my_PFileCount[move.StartSquare().File()-1][side]--;
- }
- }
- if (!move.Capture().IsEmpty())
- {
- my_Material[oside].remove_piece(move.Capture().Type());
- i = 0;
- while (i < 16 && PiecePos(oside,i) != target)
- i++;
- //assert(i < 16);
- if (i>=16)
- i = 0; // break here
- //if (move.Special() == ExtendedMove::EnPassant)
- // my_Contents[target] = Piece::EmptyPiece();
- my_PiecePos[i][oside] = Square::Invalid();
- if (move.Capture().Type() == Piece::Pawn)
- {
- my_PFileCount[target.File()-1][oside]--;
- }
- else if (move.Capture().Type() == Piece::Rook)
- {
- my_RFileCount[move.DestSquare().File()-1][oside]--;
- UpdateCastleStatus(oside,move.DestSquare());
- }
- if (my_Contents[move.DestSquare()].Type() == Piece::Pawn &&
- move.Special() != ExtendedMove::Promotion)
- {
- my_PFileCount[move.StartSquare().File()-1][side]--;
- my_PFileCount[move.DestSquare().File()-1][side]++;
- }
- }
- my_attacks.add_attacks(*this,move.DestSquare(),side);
- if (move.Special() == ExtendedMove::EnPassant)
- {
- my_attacks.add_discovered_attacks(*this,
- move.StartSquare(),move.DestSquare());
- my_attacks.remove_discovered_attacks(*this,
- move.DestSquare(),move.StartSquare());
-
- my_Contents[target] = Piece::EmptyPiece();
-
- my_attacks.add_discovered_attacks(*this,
- target,Square::Invalid());
- }
- else
- {
- my_attacks.add_discovered_attacks(*this,
- move.StartSquare(),move.DestSquare());
- if (move.Capture().IsEmpty())
- my_attacks.remove_discovered_attacks(*this,
- move.DestSquare(),move.StartSquare());
- }
- }
- my_EnPassantSq[oside] = Square::Invalid();
- my_Side = OppositeSide();
- #ifdef DEBUG_ATTACKS
- {
- Attacks new_attacks;
- new_attacks.compute_attacks(*this,White);
- new_attacks.compute_attacks(*this,Black);
- assert(new_attacks == my_attacks);
- }
- #endif
- }
-
- void Board::undo_castling(const Square &kp,
- const Square &oldkingsq, const Square &newrooksq,
- const Square &oldrooksq)
- {
- my_attacks.remove_attacks(*this,kp,my_Side);
- my_attacks.remove_attacks(*this,newrooksq,my_Side);
-
- my_Contents[kp] = Piece::EmptyPiece();
- my_Contents[oldrooksq] = Piece(Piece::Rook,my_Side);
- my_Contents[newrooksq] = Piece::EmptyPiece();
- my_Contents[oldkingsq] = Piece(Piece::King,my_Side);
- my_KingPos[my_Side] = oldkingsq;
-
- my_RFileCount[oldrooksq.File()-1][my_Side]++;
- my_RFileCount[newrooksq.File()-1][my_Side]--;
- int i = 0;
- Boolean fixed_rook = False;
- Boolean fixed_king = False;
- while (i<16)
- {
- Square sq(PiecePos(my_Side,i));
- if (sq == newrooksq)
- {
- my_PiecePos[i][my_Side] = Square::Invalid();
- if (fixed_rook && fixed_king) i++;
- }
- else if (sq == kp)
- {
- my_PiecePos[i][my_Side] = Square::Invalid();
- if (fixed_rook && fixed_king) i++;
- }
- else if (sq == Square::Invalid() && !fixed_rook)
- {
- my_PiecePos[i][my_Side] = oldrooksq;
- fixed_rook = True;
- i++;
- }
- else if (sq == Square::Invalid() && !fixed_king)
- {
- my_PiecePos[i][my_Side] = oldkingsq;
- fixed_king = True;
- i++;
- }
- else
- i++;
- }
- my_attacks.add_attacks(*this,oldkingsq,my_Side);
- my_attacks.add_attacks(*this,oldrooksq,my_Side);
- my_attacks.remove_discovered_attacks(*this,oldkingsq,newrooksq);
- }
-
- void Board::UndoMove( const ReversibleMove &rmove )
- {
- my_Side = OppositeColor(my_Side);
- if (!rmove.IsNull())
- {
-
- const ColorType opp_side = OppositeColor(my_Side);
- int i;
- if (rmove.Special() == ExtendedMove::KCastle)
- {
- Square kp = KingPos(my_Side);
- Square oldrooksq(kp+1);
- Square newrooksq(kp-1);
- Square oldkingsq(kp-2);
- undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
- }
- else if (rmove.Special() == ExtendedMove::QCastle)
- {
- Square kp = KingPos(my_Side);
- Square oldrooksq(kp-2);
- Square newrooksq(kp+1);
- Square oldkingsq(kp+2);
- undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
- }
- else
- {
- // not castling
- my_attacks.remove_attacks(*this,rmove.DestSquare(),my_Side);
- Square target;
- if (!rmove.Capture().IsEmpty())
- {
- if (rmove.Special() == ExtendedMove::EnPassant)
- target = (my_Side == White) ? rmove.DestSquare() + RankIncr :
- rmove.DestSquare() - RankIncr;
- else
- target = rmove.DestSquare();
- }
- // fix up start square:
- if (rmove.Special() == ExtendedMove::Promotion)
- {
- my_Contents[rmove.StartSquare()] = Piece(Piece::Pawn,my_Side);
- my_PFileCount[rmove.StartSquare().File()-1][my_Side]++;
- }
- else
- {
- if (rmove.Special() != ExtendedMove::EnPassant)
- my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
- switch (rmove.PieceMoved().Type())
- {
- case Piece::Pawn:
- my_PFileCount[rmove.StartSquare().File()-1][my_Side]++;
- my_PFileCount[rmove.DestSquare().File()-1][my_Side]--;
- break;
- case Piece::Rook:
- my_RFileCount[rmove.StartSquare().File()-1][my_Side]++;
- my_RFileCount[rmove.DestSquare().File()-1][my_Side]--;
- break;
- case Piece::King:
- my_KingPos[my_Side] = rmove.StartSquare();
- break;
- default:
- break;
- }
- }
- Boolean start_fix_up = False;
- i = 0; int j = 0;
- while (i<16)
- {
- if ( !start_fix_up && PiecePos(my_Side,i) == Square::Invalid() )
- {
- my_PiecePos[i][my_Side] = rmove.StartSquare();
- start_fix_up = True;
- i++;
- }
- else if (PiecePos(my_Side,i) == rmove.DestSquare())
- {
- my_PiecePos[i][my_Side] = Square::Invalid();
- if (start_fix_up) i++;
- j++;
- }
- else
- i++;
- }
- assert(j>0);
- // fix up dest square
- if (rmove.Special() == ExtendedMove::EnPassant)
- {
- my_Contents[rmove.DestSquare()] = Piece::EmptyPiece();
- my_Contents[target] = Piece(Piece::Pawn,opp_side);
- my_PFileCount[rmove.DestSquare().File()-1][opp_side]++;
- my_Material[opp_side].add_piece(Piece::Pawn);
- for (i = 0; i < 16; i++)
- {
- if( PiecePos(opp_side,i) == Square::Invalid())
- {
- my_PiecePos[i][opp_side] = target;
- break;
- }
- }
- // It tricky fixing up the attacks. Pretend we
- // made two moves: a capture "sideways" then a
- // pawn move forward, and undo them in reverse order.
- my_attacks.add_attacks(*this,target,opp_side);
- my_attacks.add_discovered_attacks(*this,
- rmove.DestSquare(),target);
- my_attacks.remove_discovered_attacks(
- *this,target,rmove.DestSquare());
-
- my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
-
- my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
- my_attacks.remove_discovered_attacks(
- *this,rmove.StartSquare(),target);
- }
- else
- {
- my_Contents[rmove.DestSquare()] = rmove.Capture();
- my_EnPassantSq[opp_side] = Square::Invalid();
- if (rmove.Special() == ExtendedMove::Promotion)
- {
- my_Material[my_Side].add_piece(Piece::Pawn);
- my_Material[my_Side].remove_piece(rmove.PromoteTo());
- }
- if (!rmove.Capture().IsEmpty())
- {
- my_Material[opp_side].add_piece(rmove.Capture().Type());
- for (i = 0; i < 16; i++)
- {
- if( PiecePos(opp_side,i) == Square::Invalid())
- {
- my_PiecePos[i][opp_side] = rmove.DestSquare();
- break;
- }
- }
- if (rmove.Capture().Type() == Piece::Rook)
- {
- my_RFileCount[rmove.DestSquare().File()-1][opp_side]++;
- }
- else if (rmove.Capture().Type() == Piece::Pawn)
- {
- my_PFileCount[rmove.DestSquare().File()-1][opp_side]++;
- }
- my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
- my_attacks.add_attacks(*this,target,OppositeColor(my_Side));
- my_attacks.remove_discovered_attacks(
- *this,rmove.StartSquare(),rmove.DestSquare());
- }
- else
- {
- // not a capture move
- my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
- my_attacks.add_discovered_attacks(*this,
- rmove.DestSquare(),rmove.StartSquare());
- my_attacks.remove_discovered_attacks(
- *this,rmove.StartSquare(),rmove.DestSquare());
- }
- }
- }
- my_EnPassantSq[my_Side] = rmove.Old_EnPassantSq(my_Side);
- my_EnPassantSq[OppositeColor(my_Side)] = rmove.Old_EnPassantSq(
- OppositeColor(my_Side));
- my_CastleStatus[my_Side] = rmove.Old_CastleStatus(my_Side);
- my_CastleStatus[OppositeColor(my_Side)] =
- rmove.Old_CastleStatus(OppositeColor(my_Side));
- }
- my_HashCode = rmove.Old_HashCode();
- #ifdef DEBUG_ATTACKS
- {
- Attacks new_attacks;
- new_attacks.compute_attacks(*this,White);
- new_attacks.compute_attacks(*this,Black);
- assert (new_attacks == my_attacks);
- }
- #endif
- }
-
- Board::CheckStatusType Board::CheckStatus() const
- {
- if (num_attacks(KingPos(Side()),OppositeSide()) > 0)
- return InCheck;
- else
- return NotInCheck;
- }
-
- static void set_bad( istream &i )
- {
- i.clear( ios::badbit | i.rdstate() );
- }
-
- istream & operator >> (istream &i, Board &board)
- {
- // read in a board position in Forsythe-Edwards (FEN) notation.
- static char buf[128];
-
- for (int j=0;j<BoardSize;j++)
- {
- board.my_Contents[j] = Piece::EmptyPiece();
- }
-
- i.getline(buf,128);
- if (!i)
- return i;
-
- Square sq;
- char *bp = buf;
- char c;
- while (isspace(*bp)) bp++;
- for (int line = 0; line < 8; line++)
- {
- int sqval = line*RankIncr;
- while ((c = *bp) != ' ' && c != '/')
- {
- Piece piece;
- if (isdigit(c))
- {
- sqval += (*bp - '0');
- bp++;
- }
- else if (isalnum(c))
- {
- if (!Square(sqval).OnBoard())
- {
- set_bad(i);
- return i;
- }
- switch(c)
- {
- case 'p': piece = Piece(Piece::Pawn,Black);
- break;
- case 'n': piece = Piece(Piece::Knight,Black);
- break;
- case 'b': piece = Piece(Piece::Bishop,Black);
- break;
- case 'r': piece = Piece(Piece::Rook,Black);
- break;
- case 'q': piece = Piece(Piece::Queen,Black);
- break;
- case 'k': piece = Piece(Piece::King,Black);
- break;
- case 'P': piece = Piece(Piece::Pawn,White);
- break;
- case 'N': piece = Piece(Piece::Knight,White);
- break;
- case 'B': piece = Piece(Piece::Bishop,White);
- break;
- case 'R': piece = Piece(Piece::Rook,White);
- break;
- case 'Q': piece = Piece(Piece::Queen,White);
- break;
- case 'K': piece = Piece(Piece::King,White);
- break;
- default:
- set_bad(i);
- return i;
- }
- board.my_Contents[sqval] = piece;
- sqval++;
- bp++;
- }
- else // not a letter or a digit
- {
- set_bad(i);
- return i;
- }
- }
- if (c=='/') ++bp; // skip delimiter
- }
- while (isspace(*bp)) bp++;
- ColorType side;
- if (toupper(*bp) == 'W')
- board.my_Side = White;
- else if (toupper(*bp) == 'B')
- board.my_Side = Black;
- else
- {
- set_bad(i);
- return i;
- }
- bp++;
- while (isspace(*bp)) bp++;
- c = *bp;
- if (c == '-')
- {
- board.my_CastleStatus[White] =
- board.my_CastleStatus[Black] = Board::CantCastleEitherSide;
- bp++;
- }
- else
- {
- int k = 0;
- for (; !isspace(*bp); bp++)
- {
- if (*bp == 'K')
- k += 1;
- else if (*bp == 'Q')
- k += 2;
- else if (*bp == 'k')
- k += 4;
- else if (*bp == 'q')
- k += 8;
- else
- {
- set_bad(i);
- return i;
- }
- }
- static Board::CastleType vals[4] =
- { Board::CantCastleEitherSide, Board::CanCastleKSide,
- Board::CanCastleQSide, Board::CanCastleEitherSide };
- board.my_CastleStatus[White] = vals[k % 4];
- board.my_CastleStatus[Black] = vals[k / 4];
- }
- while (isspace(*bp)) bp++;
- c = *bp;
- if (c == '-')
- {
- board.my_EnPassantSq[White].SetInvalid();
- board.my_EnPassantSq[Black].SetInvalid();
- }
- else if (isalpha(c))
- {
- char sqbuf[2];
- sqbuf[0] = *bp++;
- sqbuf[1] = *bp++;
- Square epsq = Square::Value(sqbuf);
- if (epsq.IsInvalid())
- {
- set_bad(i);
- return i;
- }
- board.my_EnPassantSq[board.Side()].SetInvalid();
- board.my_EnPassantSq[board.OppositeSide()] =
- Square::Value(sqbuf) - (RankIncr * Direction[board.Side()]);
- }
- else
- {
- set_bad(i);
- return i;
- }
- board.set_secondary_vars();
- return i;
- }
-
- ostream & operator << (ostream &o, Board &board)
- {
- // write out the board in Forsythe-Edwards (FEN) notation.
- for (int i=1;i<=8;i++)
- {
- int j = 1;
- while (j <= 8)
- {
- int n = 0;
- Square sq;
- Piece p;
- do
- {
- sq = Square(j,i,Black);
- p = board.my_Contents[sq];
- if (!p.IsEmpty())
- break;
- ++j; ++n;
- } while (j <= 8);
- if (n)
- o << (char)(n + '0');
- if (!p.IsEmpty())
- {
- char img = Piece::Image(p.Type());
- if (p.Color() == Black) img = tolower(img);
- o << img;
- j++;
- }
- }
- if (i != 8) o << '/';
- }
- if (board.Side() == White)
- o << " w";
- else
- o << " b";
-
- // used in I/O of castling data:
- const Boolean kcastle[6] = { True, True, False, False, False, False };
- const Boolean qcastle[6] = { True, False, True, False, False, False };
-
- // note : unfortunately FEN doesn't allow recording if castling
- // has taken place, only whether or not it is possible.
- Board::CastleType wcs = board.CastleStatus(White);
- Board::CastleType bcs = board.CastleStatus(Black);
- o << ' ';
- if (!kcastle[(int)wcs] && !qcastle[(int)bcs])
- o << '-';
- else
- {
- if (kcastle[(int)wcs])
- o << 'K';
- if (qcastle[(int)wcs])
- o << 'Q';
- if (kcastle[(int)bcs])
- o << 'k';
- if (qcastle[(int)bcs])
- o << 'q';
- }
- o << ' ';
- Square epsq(board.EnPassantSq(board.OppositeSide()));
- if (epsq.IsInvalid())
- o << '-';
- else
- {
- // FEN stores the destination square for an en passant capture;
- // we store the location of the capturable pawn.
- Square target(epsq + (RankIncr * Direction[board.Side()]));
- o << target.FileImage() << target.RankImage();
- }
- // FEN is supposed to include the halfmove and fullmove numbers,
- // but these are attributes of the game - they are not stored in
- // the board.
- o << " 0 1";
- o << endl;
- return o;
- }
-
-